﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;

namespace WFL.Threading
{
    public abstract class Batch
    {
        internal List<BatchInstance> Instances
        {
            get;
            private set;
        }
        protected readonly object InstancesLock = new object();

        public string Name
        {
            get;
            private set;
        }

        public NameValueCollection Parameters
        {
            get;
            private set;
        }

        internal BatchRuntime Runtime
        {
            get;
            set;
        }

        public Batch(string name) : this(name, null)
        {

        }

        public Batch(string name, NameValueCollection parameters)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name", "任务名称不能为空");
            }
            Name = name;
            Parameters = parameters;
            if (Parameters == null)
            {
                Parameters = new NameValueCollection();
            }
            Instances = new List<BatchInstance>();
        }

        internal BatchInstance CreateInstance()
        {
            BatchInstance item = new BatchInstance(this);
            item.Runtime = Runtime;
            lock(InstancesLock)
            {
                Instances.Add(item);
            }
            this.InstanceStateChange(item);
            return item;
        }

        public abstract void Execute(BatchInstance instance);

        internal void InstanceStateChange(BatchInstance instance)
        {
            if (instance == null)
            {
                return;
            }
            if (instance.State == BatchInstanceState.Succeeded
                || instance.State == BatchInstanceState.Cancelled
                || instance.State == BatchInstanceState.Exception)
            {
                lock (InstancesLock)
                {
                    Instances.Remove(instance);
                }
            }
            try
            {
                OnInstanceStateChange(instance);
            }
            catch (Exception ex)
            {
                //记录为引擎日志
                Runtime.OnLog(ex);
            }
        }

        protected abstract void OnInstanceStateChange(BatchInstance instance);

        protected void SetTempData(BatchInstance instance, object data)
        {
            instance.TempData = data;
        }

        protected void SetResultData(BatchInstance instance, object data)
        {
            instance.ResultData = data;
        }

        internal void CancelAll(object data)
        {
            int extraTryTimes = 4;
            while (extraTryTimes > 0 || Instances.Count > 0)
            {
                BatchInstance[] tempInstances = null;
                lock (InstancesLock)
                {
                    if (Instances.Count > 0)
                    {
                        tempInstances = new BatchInstance[Instances.Count];
                        Instances.CopyTo(tempInstances);
                    }
                    else
                    {
                        extraTryTimes--;
                    }
                }
                if (tempInstances != null)
                {
                    foreach (BatchInstance item in tempInstances)
                    {
                        item.Cancel(data);
                    }
                }
            }
        }

        public BatchInstance Get(Guid instanceId)
        {
            lock(InstancesLock)
            {
                foreach (BatchInstance item in Instances)
                {
                    if (item.Id == instanceId)
                    {
                        return item;
                    }
                }
            }
            return null;
        }

        public BatchInstance[] GetList()
        {
            lock(InstancesLock)
            {
                return Instances.ToArray();
            }
        }
    }
}